\chapter{Fundamendação Teórica}

	Neste Capítulo serão explanados os principais conceitos utilizados neste trabalho. Primeiramente apresentaremos o conceito da Visão Computacional, em seguida o conceito sobre Android e sua arquitetura e ferramenta OpenCV. Finalizando, será explanada a técnica do OpenCV e Android utilizando a ferramenta JNI e suas principais bibliotecas mapeadas para o Android.

\section{Visão Computacional}

A visão computacional procura realizar a visão humana, sendo à entrada do sistema uma imagem e a saída um conjunto de valores numéricos, que podem ou não compor outra imagem. Os processos de visão computacional iniciam-se com o processamento de imagem e pode ser dividido em três níveis:

\begin{itemize}
\item	baixo nível - são os processos que envolvem operações primitivas como a redução de ruído e melhoria de contraste da imagem;
\item	médio nível - são os processos de operações do tipo segmentação em que é feito o particionamento da imagem em regiões ou classificação em que é feito o reconhecimento dos objetos na imagem;
\item alto nível - são os processos que se relacionam  com as tarefas de cognição associadas com a visão humana.
\end{itemize}

A imagem não é interpretada da mesma forma que o ser humano identifica uma cena, mas a partir de atributos que devem ser extraídos da imagem e estão relacionados, em um sistema de tratamento de imagens, busca capturar atributos da imagem e usar os elementos minimizando o espaço de pesquisa. É necessário criar um modelo de dados para a representação sistemática do conteúdo de uma imagem. A sequência de ações para aquisição e processamento de uma imagem é mostrada na etapa a seguir, sendo as principais operações realizadas no tratamento de uma imagem:

\section{Etapas da Visão Computacional}


\subsection{Aquisição de Imagem}

Na aquisição da imagem, temos dois elementos relevantes de um sistema de visão computacional: o primeiro refere aos equipamentos que compõem o ambiente (hardware), tais como câmeras, computadores e sistemas de iluminação e o segundo elemento é o programa (software) que processa as imagens e gerencia as ações a serem realizadas.

\subsection{Pré-Processamento}

Depois de adquirida a imagem, as técnicas de pré-processamento são usadas para aprimorar a qualidade de uma imagem, corrigindo iluminação, contraste, distorções e nitidez.

\subsection{Segmentação}

A imagem exige muito em termos de requisitos do sistema, principalmente em relação à quantidade de memória, velocidade de processamento e capacidade de armazenamento. Habitualmente utilizamos esforço computacional para reduzir a transformação da imagem em uma escala reduzida de informações, através da segmentação. A ideia utilizada na segmentação chamada de \textit{thresholding} é dividir a imagem em regiões que correspondem a unidades estruturais da cena ou que distinguem os objetos de interesse, separando os objetos da imagem chamado de \textit{foreground} das informações de fundo da imagem. Entre diversas técnicas que podem ser utilizadas para a segmentação, apresentaremos algumas delas e mostraremos como utilizá-las. As técnicas de segmentação que serão apresentadas podem ser classificadas em três grupos: segmentação por detecção de borda, segmentação por corte e segmentação por crescimento de região.

\subsubsection{Segmentação por detecção de borda}

Borda em uma imagem é caracterizada por uma mudança, no nível de intensidade dos pixels. Os detectores de borda são definidos para encontrar este tipo de variação nos pixels e quando estes pixels estão próximos eles podem ser conectados formando uma borda ou um contorno e assim definindo uma região ou objeto. Variações nos níveis de intensidade dos pixels podem ser determinadas pelas derivadas primeira e/ou derivada segunda. Alguns métodos de determinação de borda utilizam estas técnicas. O processo consiste em se definir máscaras que caracterizem estas variações e em seguida fazer a operação matemática da imagem pelas máscaras.

A detecção de borda desenvolvida por Canny \cite{CANNY86}, embora seja uma técnica mais complexa, apresenta em muitos trabalhos na área, desempenho superior. O detector de bordas de Canny possui três objetivos básicos: 

\begin{itemize}
\item Baixa taxa de erro onde todas as bordas devem ser encontradas; 
\item Pontos da borda devem ser bem localizados onde as bordas localizadas devem ser próximas das bordas reais;
\item Resposta única para os pontos de uma borda onde o operador deve retornar apenas um ponto para cada ponto sobre a borda.
\end{itemize}

A técnica de Canny é representada matematicamente utilizando a otimização numérica, definindo um detector de borda baseado na primeira derivada de uma Gaussiana como apresentado na Figura \ref{Figura 2.1}.

\begin{figure}[h]
\begin{center}
$ \begin{array}{cc}
\includegraphics[scale=0.60]{urso.png} &
\includegraphics[scale=0.60]{urso2.png} \\
(a) & (b)
\end{array} $
\caption{Segmentação por detecção de borda, (a) Imagem Original, (b) Detecção de Borda}
\label{Figura 2.1}
\end{center} 
\end{figure}

\subsubsection{Segmentação por corte}


A segmentação por corte é uma técnica simples e rápida em termos computacionais. A segmentação por corte particiona uma imagem diretamente em regiões baseado simplesmente nos valores de intensidade e propriedades destes valores. A técnica verifica no histograma da imagem quantas regiões existem e segmenta a imagem baseado nesta informação. A Figura \ref{Figura 2.2} apresenta uma imagem com um possível local onde a imagem poderia ser particionada e a imagem binarizada.

\begin{figure}[h]
\begin{center}
$ \begin{array}{cc}
\includegraphics[scale=0.60]{urso7.png} &
\includegraphics[scale=0.60]{urso3.png} \\
(a) & (b)
\end{array} $
\caption{Segmentação por corte, (a) Imagem Original, (b) Segmenta por Corte}
\label{Figura 2.2}
\end{center} 
\end{figure}

Utilizando a técnica é possível definir uma região e criar uma imagem segmentada que não seja simplesmente uma imagem binária. É possível ainda fazer tratamentos no histograma para minimizar efeitos de ruídos que apareçam na imagem.

\subsubsection{Segmentação por crescimento de região}

A técnica de segmentação por crescimento de região encontra diretamente na imagem regiões agrupados por pixels ou em sub-regiões de regiões maiores com critérios de crescimento pré-definidos. Podemos agrupar os pontos utilizando uma vizinhança de influência, formando as regiões. A vizinhança analisadas com as propriedades, são medidas as similaridades o que se determinar o pixel fazendo parte ou não da região considerada. As propriedades consideradas são: cor, intensidade de nível de cinza, textura, momentos, etc. Detalhes importantes desta técnica são a definição das sementes e a definição de um critério de parada para o crescimento de regiões. A Figura \ref{Figura 2.3} apresenta uma segmentação pelo método de crescimento de região. Esta segmentação possui menos componentes ligados que a binarização.

\begin{figure}[h]
\begin{center}
$ \begin{array}{cc}
\includegraphics[scale=0.60]{urso.png} &
\includegraphics[scale=0.60]{urso4.png} \\
(a) & (b)
\end{array} $
\caption{Segmentação por crescimento de região, (a) Imagem Original, (b) Segmentada por Crescimento de Região}
\label{Figura 2.3}
\end{center} 
\end{figure}

Outra maneira para aplicação do método é subdividir a imagem inicialmente em um conjunto de regiões distintas e unir ou não as regiões de forma a atender as características que são utilizadas no processo de segmentação. Esta técnica utiliza-se uma estrutura de \textit{quadtrees}, que são árvores onde um nó possui exatos quatro filhos. As imagens correspondentes a cada filho são chamadas de \testit{quadregions ou quadimages}. O esquema do método de dividir e unir regiões são apresentados na Figura \ref{Figura 2.4}.

 \begin{figure}[h]
\centering
\fbox{\includegraphics[scale=0.60]{ursosub.png}}
\caption{Método de subdivição de imagem}
\label{Figura 2.4}
\end{figure}


\subsection{Identificação de Obejtos}

A identificação e extração de objetos de imagens são necessárias em muitos casos, pois os dados de imagens usados na entrada de um sistema de visão, nem sempre são perfeitos. Os problemas que frequentemente ocorrem estão relacionados com a oclusão, onde um objeto pode estar parcialmente escondido atrás de outro objeto, ou dois objetos compondo a mesma imagem. De forma análoga, a perda de informações ou deformações, pode ser ocasionada por ruídos na imagem devido a condições anormais de iluminação, defeitos de digitalização, e de resultados ineficientes de algoritmos de segmentação.

\subsection{Reconhecimento de Padrões}

O processamento da imagem é realizado por ambientes computacionais que operam as informações obtidas das imagens. A extração de atributos  constitui-se em uma operação permitindo definir quais elementos dos objetos nas imagens podem ser separados de outros objetos na mesma imagem. As técnicas de reconhecimento de padrões tratam da identificação de partes da imagem que possuem semelhanças. Uma grande quantidade de ferramentas matemáticas e computacionais vem sendo desenvolvidas para permitir que objetos possam ser extraídos e agrupados em classes específicas de informações. A representação da forma do objeto facilita para que seja armazenado, transmitido, comparado, reconhecido e até mesmo entendido. A representação pode ser gerada de acordo com regras simples e precisa, tendo uma forma de descrever os termos de número de componentes, primitivas, e relacionamentos entre estes componentes.


Esta é a parte onde os sistemas de visão possuem uma intersecção com a área de inteligência artificial. Para fazer o reconhecimento um sistema de visão necessita uma base de conhecimento dos objetos a ser reconhecida, esta base de conhecimento pode ser implementada diretamente no código, através, de um sistema baseado em regras, ou esta base de conhecimento pode ser aprendida a partir de um conjunto de amostras dos objetos a serem reconhecidos utilizando técnicas de aprendizado de máquina.

O reconhecimento de objetos é uma das principais funções da área de visão computacional e está relacionado diretamente com o reconhecimento de padrões. Um objeto pode ser definido por mais de um padrão, textura, forma, cor, dimensões, etc. e o reconhecimento individual de cada um destes padrões pode facilitar o reconhecimento do objeto como um todo. As técnicas de reconhecimento de padrões podem ser divididas em dois grandes grupos: estruturais, onde os padrões são descritos de forma simbólica e a estrutura é a forma como estes padrões se relacionam; o outro grupo é baseado em técnicas que utilizam teoria de decisão, neste grupo os padrões são descritos por propriedades quantitativas e deve-se decidir se o objeto possui ou não estas propriedades.


Os processos de reconhecimento de padrões podem ainda ser uma mistura das técnicas utilizadas nestes dois grupos, como o uso de um modelo estrutural para determinar o local mais provável para se encontrar partes de uma face, boca, olhos e pele, conforme apresentado na Figura \ref{Figura 2.5}. Cada uma destas partes pode agora ser reconhecida utilizando outro tipo de técnica, por exemplo, os olhos podem ser reconhecidos utilizando uma rede neural, a pele pode ser reconhecida por uma análise estatística e a boca pode ser reconhecida por um critério de distância mínima, todas são técnicas de teoria de decisão.

 \begin{figure}[h]
\centering
\fbox{\includegraphics[scale=1.00]{RP.png}}
\caption{Reconhecimento de Padrões}
\label{Figura 2.5}
\end{figure}

É difícil encontrar técnicas estruturais prontas em bibliotecas, uma vez que estas técnicas dependem da estrutura de cada objeto. Para alguns objetos específicos é possível encontrar pacotes prontos. O OpenCV não possui uma ferramenta pronta que utilize este tipo de técnica. As técnicas baseadas em teoria de decisão são mais gerais e podem ser adaptadas a diferentes tipos de objetos.

\section{Android}

	Os chamados smartphones estão dominando o mercado, tudo isso possível devido aos Sistemas Operacionais para dispositivos móvel, dominado pelo IOs da Apple e segundo lugar pelo Android. O sistema operacional Android roda sobre o núcleo Linux, desenvolvido pelo Open Handset Allience tendo a Google responsável pela gerencia do produto. Seu sistema permite aos desenvolvedores escreverem software na linguagem de programação JAVA. Podemos citar alguns trabalhos nesta área como: MoCA: Uma Arquitetura para o Desenvolvimento de Aplicações Sensíveis ao Contexto para Dispositivos Móveis \cite{VSRE06}, Acesso a Informações Médicas através do Uso de Sistemas de Computação Móvel \cite{MKTGFP04}, Protótipo para Coleta de Informações em Saúde Utilizando Dispositivos Móveis  \cite{MPL05}, Aprendizagem utilizando Dispositivos Móveis com Sistemas de Realidade Virtual \cite{MAR05}, entre outros.



\subsection{Arquitetura}

	O Android tem sua arquitetura baseada no kernel do GNU/Linux como apresentado na Figura \ref{Figura 2.6}. Este sistema funciona com abstração de camadas entre o hardware e o restante da pilha de softwares da plataforma. Este possui uma variedade recursos necessário à execução de aplicações, como:

\begin{enumerate}
	\item	Gerenciamento de memória, 
	\item	Gerenciamento de processos, 
	\item	Pilha de protocolos de rede, 
	\item	Módulo de segurança e 
	\item	Vários módulos do núcleo de infra-estrutura.
\end{enumerate}

\begin{figure}[h]
\centering
\fbox{\includegraphics[scale=0.80]{figura1.png}}
\caption{Arquitetura do Android}
\label{Figura 2.6}
\end{figure}
	
	O sistema operacional Android, tem constantes melhorias dos drivers. As aplicações do Android realiza seu próprio processo, utilizando instância da máquina virtual \textit{Dalvik}, este escrito de forma para que um dispositivo possa executar múltiplas máquinas virtuais concorrentemente de maneira eficiente.  A máquina virtual \textit{Dalvik} executa classes compiladas por um compilador Java. Arquivos .class gerados são transformados no formato .dex pela ferramenta dx, incluída no SDK (Software Development Kit) do Android esses arquivos .dex são executados pelo \textit{Dalvik}.  A máquina virtual \textit{Dalvik} usa kernel do GNU/Linux para prover funcionalidade de múltiplas \textit{threads} e gerenciamento de memória de baixo nível. Na Figura \ref{Figura 2.7}, Core Libraries contém um conjunto de bibliotecas que fornece a maioria das funcionalidades disponíveis no núcleo das bibliotecas da linguagem Java, incluindo classes para manipulação de arquivos, entrada e saída, entre outros.

\begin{figure}[h]
\centering
\fbox{\includegraphics[scale=0.80]{figura2.png}}
\caption{Core Libraries}
\label{Figura 2.7}
\end{figure}

	A máquina virtual Dalvik é otimizada para permitir executar múltiplas instâncias ao mesmo tempo em memória limitada. Cada aplicação possui seu próprio processo, permitindo instalações dinâmicas, ativações e desativações. Os desenvolvedores têm acesso completo à mesma API que é usada pelas aplicações.

	A arquitetura da aplicação é projetada para simplificar o reuso dos componentes podendo ser possível à edição de sua capacidade e qualquer outro componente. Para fazer o uso dessas capacidades existem situações que estão sujeito às restrições de segurança reforçadas pelo framework. Esse mesmo mecanismo permite que os componentes sejam substituídos por outros em tempo de desenvolvimento. Na Figura \ref{Figura 2.8} mostra o fundamento de todas as aplicações do framework, como sendo um conjunto de serviços e sistemas:

\begin{figure}[h]
\centering
\fbox{\includegraphics[scale=0.75]{figura3.png}}
\caption{Aplicações Framework}
\label{Figura 2.8}
\end{figure}

\begin{itemize}
	\item	Activity Manager (Gerenciador de atividade): Gerencia o ciclo de vida das aplicações.
	\item	Package Manager (Gerenciador de pacotes): Mantém quais aplicações estão instaladas no dispositivo.
	\item	Window Manager (Gerenciador de janelas): Gerencia as janelas das aplicações.
	\item	Telephony Manager (Gerenciador de telefonia): Componentes para acesso aos recursos de telefonia.
	\item	Content Providers (Provedores de conteúdo): Permitem que as aplicações acessem os dados de outras aplicações (como contatos) ou compartilhem os seus próprios dados.
Resource Manager (Gerenciador de recursos): Fornece acesso a recursos gráficos e arquivos de layout.
	\item	View System (Visão do sistema): Um conjunto rico e extensível de componentes de interface de usuário. As visões podem ser usadas para construir uma aplicação, elas incluem listas, grids, caixas de texto, botões, dentre outras.
	\item	Location Manager (Gerenciador de localização): Gerencia a localização do dispositivo.
	\item	Notification Manager (Gerenciador de notificações): Permite que todas as aplicações exibam alerta na barra de status.
	\item	XMPP Service (Serviço XMPP): Suporte para uso do protocolo XMPP (Extensible Messaging and Presence Protocol) [18].
\end{itemize}

	Há quatro blocos principais de construção de uma aplicação Android:
\begin{itemize}
	\item	Activity (Atividade)
	\item	Intent Receiver (Receptor de Intenção)
	\item	Service (Serviço)
	\item	Content Provider (Provedor de Conteúdo)
\end{itemize}

\section{OpenCV}

Com o aumento do uso de dispositivo móvel e a necessidade de aplicações que possam resolver problemas de análise e otimização de imagem,  estudaremos as implementações de técnicas de visão computacional sobre dispositivos móvel usando Android. Uma das bibliotecas disponíveis e necessárias para implementações dos métodos e técnicas da visão computacional é a OpenCV (Open Source Computer Vision Library), desenvolvida pela INTEL no ano de 2000 \cite{MS09}.  

	A biblioteca OpenCV foi desenvolvida pela Intel e possui mais de 500 funções \cite{BK08}. O objetivo desta biblioteca é de tornar a visão computacional acessível aos usuários e programadores nas áreas como a interação humana-computador em tempo real, biotecnologia, medicina, indústria, aplicações militares, veículos autônomos e a robótica. Um programa utilizando a biblioteca OpenCV, ao ser executado, automaticamente carrega a DLL (Dynamic Linked Library) que detecta o tipo de processador. O pacote OpenCV é oferecida a biblioteca IPL (Image Processing Library). OpenCV depende parcialmente desta biblioteca, além de documentação e um conjunto de códigos exemplos \cite{MS09}. A biblioteca está dividida em cinco grupos de funções:

\begin{itemize}
	\item	Processamento de imagens;
	\item	Análise estrutural;
	\item	Análise de movimento e rastreamento de objetos; 
	\item Reconhecimento de padrões e;
	\item	Calibração de câmera e reconstrução 3D.
\end{itemize}

	OpenCV é uma biblioteca multiplataforma e totalmente livre ao uso acadêmico o qual possui módulos de processamento de imagens e vídeo I/O, estrutura de dados, álgebra linear, GUI (Interface Gráfica do Usuário) básica com sistema de janelas independentes, controle de mouse e teclado, além de mais de 500 algoritmos de visão computacional como: filtros de imagem, calibração de câmera, reconhecimento de objetos, análise estrutural, entre outros. O seu processamento é em tempo real e foi desenvolvida na linguagem C, dando suporte a programadores que utilizam JAVA, Python e Visual Basic \cite{BK08}.
	
\section{JNI}

O JNI é uma interface de comunicação (API) desenvolvida pela Sun que permitem aos códigos executados pela VM (Java Virtual Machine) interoperarem de forma bidirecional com aplicações e bibliotecas desenvolvidas de outras linguagens, como C, assembly ou Delphi. Quando desenvolvemos aplicações utilizando Java podemos nos deparar com situações onde esta linguagem pode não atender ou não ser a solução ótima para um dado problema, por exemplo, acesso a uma biblioteca de hardware desenvolvida em C ou problemas de desempenho.

JNI tem como principal objetivo e qualidade de "driblar" as restrições impostas pelo uso da VM. Com ele podemos acessar pela classe do Java a bibliotecas desenvolvidas em linguagens com maior suporte a hardware (baixo nível) ou desenvolver em C, algoritmos críticos onde o desempenho é primordial. Inicialmente o JNI só possuía uma ferramenta que atendia somente C, porém estudiosos interessados nesta solução disponibilizam outras ferramentas para facilitar a comunicação com outras linguagens, como Delphi. Utilizando JNI e possível, por exemplo: trabalhar com objetos Java, incluindo arrays chamar métodos Java gerar ou tratar exceções carregar e obter informações das classes. As funções nativas são aplicadas de modo separado e fornece uma interface um pouco mais simples com JNI.

A JNI é um conjunto de instruções que serve, principalmente, para “traduzir” os dados da linguagem C para Java e vice-versa. Para que possa existir essa comunicação, devem ser seguidos passos, e utilizar algumas ferramentas que o Java fornece, como por exemplo, o javah, que é utilizado para criar os arquivos de cabeçalho (header) do C. Todos os métodos do Java que serão escritos em C poderão ser declarados em qualquer classe, sempre com a notação native. Feito isso, para cada classe que possui um método nativo, deve-se chamar o comando javah e passá-la como parâmetro. Ele criará um arquivo com extensão .h, onde possui o protótipo de todas as funções que deverão ser implementadas em C, uma para cada método nativo do Java. Na classe onde existe algum método nativo deve ser indicado o uso da biblioteca C, com a instrução System.loadLibrary (“nomeDaBiblioteca” ). Feito isso, toda vez que algum desses métodos for chamado, a função correspondente na biblioteca nativa será invocada \cite{FCAS02}. A Figura \ref{Figura 2.9} mostra a arquitetura padrão para a interface JNI.


\begin{figure}[h]
\centering
\fbox{\includegraphics[scale=0.75]{jni2.png}}
\caption{Arquitetura padrão JNI}
\label{Figura 2.9}
\end{figure}

Porém existem desvantagens em sua implementação, como: 

\begin{itemize}
	\item Poucas ferramentas para facilitar a criação das interfaces de comunicação;
	\item O código nativo irá suportar somente a plataforma suportada pela sua linguagem, restringindo uma das principais qualidades da VM, ser multiplataforma.
\item	Erros sutis no uso de JNI podem desestabilizar a JVM inteira de forma que são muito difíceis de reproduzir e depurar;
		\item	Apenas aplicações e applets assinados podem invocar JNI;
Uma aplicação que se baseia em JNI perde a portabilidade da plataforma Java oferece;
		\item	O quadro JNI não fornece qualquer coleta de lixo automática de recursos não-JVM  na memória alocada pelo código em execução no lado nativo; 
Verificação de erros é uma obrigação ou tem o potencial para derrubar o lado JNI e da JVM;
		\item	Entre outras.
\end{itemize}

	Java Native Interface (JNI) é uma ferramenta robusta da plataforma JAVA, as aplicações que usam JNI podem incorporar código nativo escrito na linguagem de programação C, para que possa ser usado na linguagem de programação JAVA, permitindo aos programadores a vantagem de usar toda força da plataforma JAVA \cite{LIA99}. Alguns programadores referenciam a JNI como uma válvula de escape para as aplicações desenvolvidas em JAVA permitindo adicionar funcionalidade JAVA que o padrão JAVA API não fornece, no entanto deve-se tomar cuidado com algumas armadilhas dessa ferramenta. Na Figura \ref{Figura 2.10} ilustra outra representação das camadas de comunicação da aplicação JNI.
	
\begin{figure}[h]
\centering
\fbox{\includegraphics[scale=0.75]{jni.png}}
\caption{Representação das camadas de comunicação da aplicação JNI}
\label{Figura 2.10}
\end{figure}
	
\section{OpenCV e JNI}
A partir do OpenCV da versão 2.3 foi disponibilizada uma interface JNI para fazer essa comunicação entre as bibliotecas do OpenCV escritas em C com a máquina Virtual Dalvik. Dessa forma não é necessário o desenvolvimento de códigos nativos para o processamento de imagens em aplicativos móveis, embora seja recomendável verificar se existe algum ganho de desempenho significativo no sistema ao utilizar código nativo. A Figura \ref{Figura 2.11} mostra o fluxo de execução do OpenCV dentro do sistema Android.

\begin{figure}[h]
\centering
\fbox{\includegraphics[scale=0.75]{JNIOpenCV.png}}
\caption{Arquitetura de execução do OpenCV no sistema Android}
\label{Figura 2.11}
\end{figure}

O manual de referência existente OpenCV não contém notas sobre a presença de cada função OpenCV em Java API. A Tabela \ref{Tabela 2.12} mostra o mapeamento dos pacotes da biblioteca OpenCV, mostrando testes gerados, testes implementados e testes implementados que foram aprovados.

 
\begin{table}[htbp]
  \centering
 
    \begin{tabular}{|r|r|r|r|r|}
    \hline
    \multicolumn{1}{|c|}{\textbf{Pacotes}} & \multicolumn{1}{c|}{\textbf{Gerados}} & \multicolumn{1}{c|}{\textbf{Implementados}} & \multicolumn{1}{c|}{\textbf{Aprovados}} & \multicolumn{1}{c|}{\textbf{Porcentagem}} \\
    \hline
    org.opencv.android & \multicolumn{1}{c|}{6} & \multicolumn{1}{c|}{0} & \multicolumn{1}{c|}{0} & 0\% \\
    \hline
    org.opencv.calib3d & \multicolumn{1}{c|}{113} & \multicolumn{1}{c|}{13} & \multicolumn{1}{c|}{13} & 12\% \\
    \hline
    org.opencv.core & \multicolumn{1}{c|}{374} & \multicolumn{1}{c|}{374} & \multicolumn{1}{c|}{374} & 100\% \\
    \hline
    org.opencv.features2d & \multicolumn{1}{c|}{642} & \multicolumn{1}{c|}{160} & \multicolumn{1}{c|}{160} & 25\% \\
    \hline
    org.opencv.highgui & \multicolumn{1}{c|}{21} & \multicolumn{1}{c|}{16} & \multicolumn{1}{c|}{16} & 76\% \\
    \hline
    org.opencv.imgproc & \multicolumn{1}{c|}{262} & \multicolumn{1}{c|}{146} & \multicolumn{1}{c|}{146} & 56\% \\
    \hline
    org.opencv.ml & \multicolumn{1}{c|}{241} & \multicolumn{1}{c|}{19} & \multicolumn{1}{c|}{19} & 8\% \\
    \hline
    org.opencv.objdetect & \multicolumn{1}{c|}{84} & \multicolumn{1}{c|}{8} & \multicolumn{1}{c|}{8} & 10\% \\
    \hline
    org.opencv.utils & \multicolumn{1}{c|}{41} & \multicolumn{1}{c|}{29} & \multicolumn{1}{c|}{29} & 71\% \\
    \hline
    org.opencv.video & \multicolumn{1}{c|}{28} & \multicolumn{1}{c|}{3} & \multicolumn{1}{c|}{3} & 11\% \\
    \hline
    org.opencv (total) & 42\%  & 42\%  & 42\%  & 42\% \\
    \hline
    \end{tabular}
     \caption{Mapeamento da biblioteca OpenCV (última atualização 2011-08-12 14h09min efetuada por Andrey Kamaev).}
  \label{Tabela 2.12}
\end{table}
